/**
 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "plugins/ecmascript/runtime/base/string_helper.h"
#include "plugins/ecmascript/runtime/base/builtins_base.h"
#include "plugins/ecmascript/runtime/ecma_vm.h"
#include "plugins/ecmascript/runtime/global_env.h"
#include "plugins/ecmascript/runtime/js_date.h"
#include "plugins/ecmascript/runtime/js_function.h"
#include "plugins/ecmascript/runtime/js_thread.h"
#include "plugins/ecmascript/tests/runtime/common/test_helper.h"
#include "utils/bit_utils.h"

// NOLINTNEXTLINE(google-build-using-namespace)
using namespace ark::ecmascript;
// NOLINTNEXTLINE(google-build-using-namespace)
using namespace ark::ecmascript::builtins;

// NOLINTBEGIN(readability-magic-numbers)

namespace ark::test {
const char NEG = '-';
const char PLUS = '+';
const int STR_LENGTH_OTHERS = 2;
const int MINUTE_PER_HOUR = 60;
const int CHINA_BEFORE_1901_MIN = 485;
const int CHINA_AFTER_1901_MIN = 480;
const int64_t CHINA_BEFORE_1900_MS = -2177481943000;
class BuiltinsDateTest : public testing::Test {
public:
    static void SetUpTestCase()
    {
        GTEST_LOG_(INFO) << "SetUpTestCase";
    }

    static void TearDownTestCase()
    {
        GTEST_LOG_(INFO) << "TearDownCase";
    }

    void SetUp() override
    {
        TestHelper::CreateEcmaVMWithScope(instance_, thread_, scope_);
    }

    void TearDown() override
    {
        TestHelper::DestroyEcmaVMWithScope(instance_, scope_);
    }

protected:
    // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes)
    JSThread *thread_ {nullptr};

private:
    PandaVM *instance_ {nullptr};
    EcmaHandleScope *scope_ {nullptr};
};

JSHandle<JSDate> JSDateCreateTest(JSThread *thread)
{
    EcmaVM *ecmaVm = thread->GetEcmaVM();
    ObjectFactory *factory = ecmaVm->GetFactory();
    JSHandle<GlobalEnv> globalEnv = ecmaVm->GetGlobalEnv();
    JSHandle<JSTaggedValue> dateFunction = globalEnv->GetDateFunction();
    JSHandle<JSDate> dateObject =
        JSHandle<JSDate>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(dateFunction), dateFunction));
    return dateObject;
}

static std::unique_ptr<EcmaRuntimeCallInfo> CreateAndSetRuntimeCallInfo(JSThread *thread, ArraySizeT argvLength,
                                                                        JSTaggedValue thisValue)
{
    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), argvLength);
    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo->SetThis(thisValue);
    return ecmaRuntimeCallInfo;
}

TEST_F(BuiltinsDateTest, SetGetDate)
{
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);

    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 6, jsDate.GetTaggedValue());
    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<double>(2)));

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    [[maybe_unused]] JSTaggedValue result1 = date::proto::SetDate(ecmaRuntimeCallInfo.get());
    JSTaggedValue result2 = date::proto::GetDate(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result2.GetRawData(), JSTaggedValue(static_cast<double>(2)).GetRawData());
}

TEST_F(BuiltinsDateTest, SetGetUTCDate)
{
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);

    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 6, jsDate.GetTaggedValue());
    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<double>(2)));

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    [[maybe_unused]] JSTaggedValue result3 = date::proto::SetUTCDate(ecmaRuntimeCallInfo.get());
    JSTaggedValue result4 = date::proto::GetUTCDate(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result4.GetRawData(), JSTaggedValue(static_cast<double>(2)).GetRawData());
}

TEST_F(BuiltinsDateTest, SetGetMinusUTCDate)
{
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);

    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 6, jsDate.GetTaggedValue());
    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<double>(-2)));

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    [[maybe_unused]] JSTaggedValue result3 = date::proto::SetUTCDate(ecmaRuntimeCallInfo.get());
    JSTaggedValue result4 = date::proto::GetUTCDate(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result4.GetRawData(), JSTaggedValue(static_cast<double>(29)).GetRawData());
}

TEST_F(BuiltinsDateTest, SetGetFullYear)
{
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);

    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 10, jsDate.GetTaggedValue());
    // 2018 : test case
    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<double>(2018)));
    // 10 : test case
    ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<double>(10)));
    // 2, 6 : test case
    ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<double>(6)));

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    date::proto::SetFullYear(ecmaRuntimeCallInfo.get());
    JSTaggedValue result1 = date::proto::GetFullYear(ecmaRuntimeCallInfo.get());
    // 2018 : test case
    ASSERT_EQ(result1.GetRawData(), JSTaggedValue(static_cast<double>(2018)).GetRawData());

    JSTaggedValue result2 = date::proto::GetMonth(ecmaRuntimeCallInfo.get());
    // 10 : test case
    ASSERT_EQ(result2.GetRawData(), JSTaggedValue(static_cast<double>(10)).GetRawData());

    JSTaggedValue result3 = date::proto::GetDate(ecmaRuntimeCallInfo.get());
    // 6 : test case
    ASSERT_EQ(result3.GetRawData(), JSTaggedValue(static_cast<double>(6)).GetRawData());
}

TEST_F(BuiltinsDateTest, SetGetUTCFullYear)
{
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);

    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 10, jsDate.GetTaggedValue());
    // 2018 : test case
    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<double>(2018)));
    // 10 : test case
    ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<double>(10)));
    // 2, 6 : test case
    ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<double>(6)));

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    date::proto::SetUTCFullYear(ecmaRuntimeCallInfo.get());
    JSTaggedValue result4 = date::proto::GetUTCFullYear(ecmaRuntimeCallInfo.get());
    // 2018 : test case
    ASSERT_EQ(result4.GetRawData(), JSTaggedValue(static_cast<double>(2018)).GetRawData());

    JSTaggedValue result5 = date::proto::GetUTCMonth(ecmaRuntimeCallInfo.get());
    // 10 : test case
    ASSERT_EQ(result5.GetRawData(), JSTaggedValue(static_cast<double>(10)).GetRawData());

    JSTaggedValue result6 = date::proto::GetUTCDate(ecmaRuntimeCallInfo.get());
    // 6 : test case
    ASSERT_EQ(result6.GetRawData(), JSTaggedValue(static_cast<double>(6)).GetRawData());
}

TEST_F(BuiltinsDateTest, SetGetMinusFullYear)
{
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);
    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 10, jsDate.GetTaggedValue());
    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<double>(-2018)));
    ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<double>(-10)));
    ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<double>(-6)));

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    date::proto::SetFullYear(ecmaRuntimeCallInfo.get());
    JSTaggedValue result1 = date::proto::GetFullYear(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result1.GetRawData(), JSTaggedValue(static_cast<double>(-2019)).GetRawData());

    JSTaggedValue result2 = date::proto::GetMonth(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result2.GetRawData(), JSTaggedValue(static_cast<double>(1)).GetRawData());

    JSTaggedValue result3 = date::proto::GetDate(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result3.GetRawData(), JSTaggedValue(static_cast<double>(22)).GetRawData());
}

TEST_F(BuiltinsDateTest, SetGetMinusUTCFullYear)
{
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);

    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 10, jsDate.GetTaggedValue());
    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<double>(-2018)));
    ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<double>(-10)));
    ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<double>(-6)));

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    date::proto::SetUTCFullYear(ecmaRuntimeCallInfo.get());
    JSTaggedValue result4 = date::proto::GetUTCFullYear(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result4.GetRawData(), JSTaggedValue(static_cast<double>(-2019)).GetRawData());

    JSTaggedValue result5 = date::proto::GetUTCMonth(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result5.GetRawData(), JSTaggedValue(static_cast<double>(1)).GetRawData());

    JSTaggedValue result6 = date::proto::GetUTCDate(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result6.GetRawData(), JSTaggedValue(static_cast<double>(22)).GetRawData());
}

TEST_F(BuiltinsDateTest, SetGetHours)
{
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);

    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 12, jsDate.GetTaggedValue());
    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<double>(18)));
    ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<double>(10)));
    ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<double>(6)));
    ecmaRuntimeCallInfo->SetCallArg(3, JSTaggedValue(static_cast<double>(111)));

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    date::proto::SetHours(ecmaRuntimeCallInfo.get());
    JSTaggedValue result1 = date::proto::GetHours(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result1.GetRawData(), JSTaggedValue(static_cast<double>(18)).GetRawData());

    JSTaggedValue result2 = date::proto::GetMinutes(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result2.GetRawData(), JSTaggedValue(static_cast<double>(10)).GetRawData());

    JSTaggedValue result3 = date::proto::GetSeconds(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result3.GetRawData(), JSTaggedValue(static_cast<double>(6)).GetRawData());

    JSTaggedValue result4 = date::proto::GetMilliseconds(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result4.GetRawData(), JSTaggedValue(static_cast<double>(111)).GetRawData());
}

TEST_F(BuiltinsDateTest, SetGetUTCHours)
{
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);

    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 12, jsDate.GetTaggedValue());
    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<double>(18)));
    ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<double>(10)));
    ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<double>(6)));
    ecmaRuntimeCallInfo->SetCallArg(3, JSTaggedValue(static_cast<double>(111)));

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    date::proto::SetUTCHours(ecmaRuntimeCallInfo.get());
    JSTaggedValue result5 = date::proto::GetUTCHours(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result5.GetRawData(), JSTaggedValue(static_cast<double>(18)).GetRawData());

    JSTaggedValue result6 = date::proto::GetUTCMinutes(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result6.GetRawData(), JSTaggedValue(static_cast<double>(10)).GetRawData());

    JSTaggedValue result7 = date::proto::GetUTCSeconds(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result7.GetRawData(), JSTaggedValue(static_cast<double>(6)).GetRawData());

    JSTaggedValue result8 = date::proto::GetUTCMilliseconds(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result8.GetRawData(), JSTaggedValue(static_cast<double>(111)).GetRawData());
}

TEST_F(BuiltinsDateTest, SetGetMinusHours)
{
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);

    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 12, jsDate.GetTaggedValue());
    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<double>(-18)));
    ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<double>(-10)));
    ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<double>(-6)));
    ecmaRuntimeCallInfo->SetCallArg(3, JSTaggedValue(static_cast<double>(-111)));

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    date::proto::SetHours(ecmaRuntimeCallInfo.get());
    JSTaggedValue result1 = date::proto::GetHours(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result1.GetRawData(), JSTaggedValue(static_cast<double>(5)).GetRawData());

    JSTaggedValue result2 = date::proto::GetMinutes(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result2.GetRawData(), JSTaggedValue(static_cast<double>(49)).GetRawData());

    JSTaggedValue result3 = date::proto::GetSeconds(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result3.GetRawData(), JSTaggedValue(static_cast<double>(53)).GetRawData());

    JSTaggedValue result4 = date::proto::GetMilliseconds(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result4.GetRawData(), JSTaggedValue(static_cast<double>(889)).GetRawData());
}

TEST_F(BuiltinsDateTest, SetGetMinusUTCHours)
{
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);

    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 12, jsDate.GetTaggedValue());
    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<double>(-18)));
    ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<double>(-10)));
    ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<double>(-6)));
    ecmaRuntimeCallInfo->SetCallArg(3, JSTaggedValue(static_cast<double>(-111)));

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    date::proto::SetUTCHours(ecmaRuntimeCallInfo.get());
    JSTaggedValue result5 = date::proto::GetUTCHours(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result5.GetRawData(), JSTaggedValue(static_cast<double>(5)).GetRawData());

    JSTaggedValue result6 = date::proto::GetUTCMinutes(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result6.GetRawData(), JSTaggedValue(static_cast<double>(49)).GetRawData());

    JSTaggedValue result7 = date::proto::GetUTCSeconds(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result7.GetRawData(), JSTaggedValue(static_cast<double>(53)).GetRawData());

    JSTaggedValue result8 = date::proto::GetUTCMilliseconds(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result8.GetRawData(), JSTaggedValue(static_cast<double>(889)).GetRawData());
}

TEST_F(BuiltinsDateTest, SetGetMilliseconds)
{
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);

    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 6, jsDate.GetTaggedValue());
    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<double>(100)));

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    JSTaggedValue result1 = date::proto::SetMilliseconds(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result1.GetRawData(), JSTaggedValue(static_cast<double>(100)).GetRawData());

    JSTaggedValue result2 = date::proto::GetMilliseconds(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result2.GetRawData(), JSTaggedValue(static_cast<double>(100)).GetRawData());
}

TEST_F(BuiltinsDateTest, SetGetUTCMilliseconds)
{
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);

    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 6, jsDate.GetTaggedValue());
    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<double>(100)));

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    JSTaggedValue result3 = date::proto::SetUTCMilliseconds(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result3.GetRawData(), JSTaggedValue(static_cast<double>(100)).GetRawData());

    JSTaggedValue result4 = date::proto::GetUTCMilliseconds(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result4.GetRawData(), JSTaggedValue(static_cast<double>(100)).GetRawData());
}

TEST_F(BuiltinsDateTest, SetGetMinutes)
{
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);

    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 10, jsDate.GetTaggedValue());
    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<double>(10)));
    ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<double>(6)));
    ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<double>(111)));

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    date::proto::SetMinutes(ecmaRuntimeCallInfo.get());
    JSTaggedValue result1 = date::proto::GetMinutes(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result1.GetRawData(), JSTaggedValue(static_cast<double>(10)).GetRawData());

    JSTaggedValue result2 = date::proto::GetSeconds(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result2.GetRawData(), JSTaggedValue(static_cast<double>(6)).GetRawData());

    JSTaggedValue result3 = date::proto::GetMilliseconds(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result3.GetRawData(), JSTaggedValue(static_cast<double>(111)).GetRawData());
}

TEST_F(BuiltinsDateTest, SetGetUTCMinutes)
{
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);

    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 10, jsDate.GetTaggedValue());
    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<double>(10)));
    ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<double>(6)));
    ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<double>(111)));

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    date::proto::SetUTCMinutes(ecmaRuntimeCallInfo.get());
    JSTaggedValue result4 = date::proto::GetUTCMinutes(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result4.GetRawData(), JSTaggedValue(static_cast<double>(10)).GetRawData());

    JSTaggedValue result5 = date::proto::GetUTCSeconds(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result5.GetRawData(), JSTaggedValue(static_cast<double>(6)).GetRawData());

    JSTaggedValue result6 = date::proto::GetUTCMilliseconds(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result6.GetRawData(), JSTaggedValue(static_cast<double>(111)).GetRawData());
}

TEST_F(BuiltinsDateTest, SetGetMonth)
{
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);

    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 8, jsDate.GetTaggedValue());
    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<double>(8)));
    ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<double>(3)));

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    date::proto::SetMonth(ecmaRuntimeCallInfo.get());
    JSTaggedValue result1 = date::proto::GetMonth(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result1.GetRawData(), JSTaggedValue(static_cast<double>(8)).GetRawData());

    JSTaggedValue result2 = date::proto::GetDate(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result2.GetRawData(), JSTaggedValue(static_cast<double>(3)).GetRawData());
}

TEST_F(BuiltinsDateTest, SetGetUTCMonth)
{
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);

    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 8, jsDate.GetTaggedValue());
    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<double>(8)));
    ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<double>(3)));

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    date::proto::SetUTCMonth(ecmaRuntimeCallInfo.get());
    JSTaggedValue result3 = date::proto::GetUTCMonth(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result3.GetRawData(), JSTaggedValue(static_cast<double>(8)).GetRawData());

    JSTaggedValue result4 = date::proto::GetUTCDate(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result4.GetRawData(), JSTaggedValue(static_cast<double>(3)).GetRawData());
}

TEST_F(BuiltinsDateTest, SetGetSeconds)
{
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);

    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 8, jsDate.GetTaggedValue());
    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<double>(59)));
    ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<double>(123)));

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    date::proto::SetSeconds(ecmaRuntimeCallInfo.get());
    JSTaggedValue result1 = date::proto::GetSeconds(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result1.GetRawData(), JSTaggedValue(static_cast<double>(59)).GetRawData());

    JSTaggedValue result2 = date::proto::GetMilliseconds(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result2.GetRawData(), JSTaggedValue(static_cast<double>(123)).GetRawData());
}

TEST_F(BuiltinsDateTest, SetGetUTCSeconds)
{
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);

    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 8, jsDate.GetTaggedValue());
    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<double>(59)));
    ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<double>(123)));

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    date::proto::SetUTCSeconds(ecmaRuntimeCallInfo.get());
    JSTaggedValue result3 = date::proto::GetUTCSeconds(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result3.GetRawData(), JSTaggedValue(static_cast<double>(59)).GetRawData());

    JSTaggedValue result4 = date::proto::GetUTCMilliseconds(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result4.GetRawData(), JSTaggedValue(static_cast<double>(123)).GetRawData());
}

TEST_F(BuiltinsDateTest, SetGetTime)
{
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);

    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 6, jsDate.GetTaggedValue());
    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<double>(2)));

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    JSTaggedValue result1 = date::proto::SetTime(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result1.GetRawData(), JSTaggedValue(static_cast<double>(2)).GetRawData());

    JSTaggedValue result2 = date::proto::GetTime(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result2.GetRawData(), JSTaggedValue(static_cast<double>(2)).GetRawData());
}

TEST_F(BuiltinsDateTest, UTC)
{
    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 12, JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(2020.982));
    ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(10.23));
    ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(4.32));
    ecmaRuntimeCallInfo->SetCallArg(3, JSTaggedValue(11.32));

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    JSTaggedValue result1 = date::UTC(ecmaRuntimeCallInfo.get());
    TestHelper::TearDownFrame(thread_, prev);
    ASSERT_EQ(result1.GetRawData(), JSTaggedValue(static_cast<double>(1604487600000)).GetRawData());

    auto ecmaRuntimeCallInfo1 = CreateAndSetRuntimeCallInfo(thread_, 18, JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo1->SetCallArg(0, JSTaggedValue(2020.982));
    ecmaRuntimeCallInfo1->SetCallArg(1, JSTaggedValue(10.23));
    ecmaRuntimeCallInfo1->SetCallArg(2, JSTaggedValue(4.32));
    ecmaRuntimeCallInfo1->SetCallArg(3, JSTaggedValue(11.32));
    ecmaRuntimeCallInfo1->SetCallArg(4, JSTaggedValue(45.1));
    ecmaRuntimeCallInfo1->SetCallArg(5, JSTaggedValue(34.321));
    ecmaRuntimeCallInfo1->SetCallArg(6, JSTaggedValue(static_cast<int32_t>(231)));

    prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo1.get());
    result1 = date::UTC(ecmaRuntimeCallInfo1.get());
    TestHelper::TearDownFrame(thread_, prev);
    ASSERT_EQ(result1.GetRawData(), JSTaggedValue(static_cast<double>(1604490334231)).GetRawData());

    auto ecmaRuntimeCallInfo2 = CreateAndSetRuntimeCallInfo(thread_, 10, JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo2->SetCallArg(0, JSTaggedValue(10.23));
    ecmaRuntimeCallInfo2->SetCallArg(1, JSTaggedValue(4.32));
    ecmaRuntimeCallInfo2->SetCallArg(2, JSTaggedValue(11.32));

    prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo2.get());
    result1 = date::UTC(ecmaRuntimeCallInfo2.get());
    TestHelper::TearDownFrame(thread_, prev);
    ASSERT_EQ(result1.GetRawData(), JSTaggedValue(static_cast<double>(-1882224000000)).GetRawData());

    auto ecmaRuntimeCallInfo3 = CreateAndSetRuntimeCallInfo(thread_, 6, JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo3->SetCallArg(0, JSTaggedValue(1994.982));

    prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo3.get());
    result1 = date::UTC(ecmaRuntimeCallInfo3.get());
    TestHelper::TearDownFrame(thread_, prev);
    ASSERT_EQ(result1.GetRawData(), JSTaggedValue(static_cast<double>(757382400000)).GetRawData());

    auto ecmaRuntimeCallInfo4 = CreateAndSetRuntimeCallInfo(thread_, 6, JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo4->SetCallArg(0, JSTaggedValue(19999944.982));

    prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo4.get());
    result1 = date::UTC(ecmaRuntimeCallInfo4.get());
    TestHelper::TearDownFrame(thread_, prev);
    ASSERT_EQ(result1.GetRawData(), JSTaggedValue(static_cast<double>(base::NAN_VALUE)).GetRawData());
}

void SetAllYearAndHours(JSThread *thread, const JSHandle<JSDate> &jsDate)
{
    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread, 10, jsDate.GetTaggedValue());
    // 2018 : test case
    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<double>(2018)));
    // 10 : test case
    ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<double>(10)));
    // 2, 6 : test case
    ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<double>(6)));

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
    date::proto::SetFullYear(ecmaRuntimeCallInfo.get());
    TestHelper::TearDownFrame(thread, prev);

    auto ecmaRuntimeCallInfo1 = CreateAndSetRuntimeCallInfo(thread, 12, jsDate.GetTaggedValue());
    // 18 : test case
    ecmaRuntimeCallInfo1->SetCallArg(0, JSTaggedValue(static_cast<double>(18)));
    // 10 : test case
    ecmaRuntimeCallInfo1->SetCallArg(1, JSTaggedValue(static_cast<double>(10)));
    // 2, 6 : test case
    ecmaRuntimeCallInfo1->SetCallArg(2, JSTaggedValue(static_cast<double>(6)));
    // 3, 111 : test case
    ecmaRuntimeCallInfo1->SetCallArg(3, JSTaggedValue(static_cast<double>(111)));

    prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1.get());
    date::proto::SetHours(ecmaRuntimeCallInfo1.get());
    TestHelper::TearDownFrame(thread, prev);
}

void SetAll1(JSThread *thread, const JSHandle<JSDate> &jsDate)
{
    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread, 10, jsDate.GetTaggedValue());
    // 1900 : test case
    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<double>(1900)));
    // 11 : test case
    ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<double>(11)));
    // 2, 31 : test case
    ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<double>(31)));

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
    date::proto::SetFullYear(ecmaRuntimeCallInfo.get());
    TestHelper::TearDownFrame(thread, prev);

    auto ecmaRuntimeCallInfo1 = CreateAndSetRuntimeCallInfo(thread, 12, jsDate.GetTaggedValue());
    // 23 : test case
    ecmaRuntimeCallInfo1->SetCallArg(0, JSTaggedValue(static_cast<double>(23)));
    // 54 : test case
    ecmaRuntimeCallInfo1->SetCallArg(1, JSTaggedValue(static_cast<double>(54)));
    // 2, 16 : test case
    ecmaRuntimeCallInfo1->SetCallArg(2, JSTaggedValue(static_cast<double>(16)));
    // 3, 888 : test case
    ecmaRuntimeCallInfo1->SetCallArg(3, JSTaggedValue(static_cast<double>(888)));

    prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1.get());
    date::proto::SetHours(ecmaRuntimeCallInfo1.get());
    TestHelper::TearDownFrame(thread, prev);
}

void SetAll2(JSThread *thread, const JSHandle<JSDate> &jsDate)
{
    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread, 10, jsDate.GetTaggedValue());
    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<double>(1901)));  // 1901 : test case
    ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<double>(0)));
    ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<double>(1)));  // 2 : test case

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
    date::proto::SetFullYear(ecmaRuntimeCallInfo.get());
    TestHelper::TearDownFrame(thread, prev);

    // 12 : test case
    auto ecmaRuntimeCallInfo1 = CreateAndSetRuntimeCallInfo(thread, 12, jsDate.GetTaggedValue());
    ecmaRuntimeCallInfo1->SetCallArg(0, JSTaggedValue(static_cast<double>(0)));
    ecmaRuntimeCallInfo1->SetCallArg(1, JSTaggedValue(static_cast<double>(3)));    // 3 : test case
    ecmaRuntimeCallInfo1->SetCallArg(2, JSTaggedValue(static_cast<double>(21)));   // 2, 21 : test case
    ecmaRuntimeCallInfo1->SetCallArg(3, JSTaggedValue(static_cast<double>(129)));  // 3, 129 : test case

    prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1.get());
    date::proto::SetHours(ecmaRuntimeCallInfo1.get());
    TestHelper::TearDownFrame(thread, prev);
}

TEST_F(BuiltinsDateTest, parse)
{
    JSHandle<EcmaString> str =
        thread_->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString("2020-11-19T12:18:18.132Z");
    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 6, JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo->SetCallArg(0, str.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    JSTaggedValue result1 = date::Parse(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result1.GetRawData(), JSTaggedValue(static_cast<double>(1605788298132)).GetRawData());

    JSHandle<EcmaString> str1 = thread_->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString("2020-11-19Z");
    auto ecmaRuntimeCallInfo1 = CreateAndSetRuntimeCallInfo(thread_, 6, JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo1->SetCallArg(0, str1.GetTaggedValue());

    prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo1.get());
    result1 = date::Parse(ecmaRuntimeCallInfo1.get());
    TestHelper::TearDownFrame(thread_, prev);
    ASSERT_EQ(result1.GetRawData(), JSTaggedValue(static_cast<double>(1605744000000)).GetRawData());

    JSHandle<EcmaString> str2 =
        thread_->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString("2020-11T12:18:17.231+08:00");
    auto ecmaRuntimeCallInfo2 = CreateAndSetRuntimeCallInfo(thread_, 6, JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo2->SetCallArg(0, str2.GetTaggedValue());

    prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo2.get());
    result1 = date::Parse(ecmaRuntimeCallInfo2.get());
    TestHelper::TearDownFrame(thread_, prev);
    ASSERT_EQ(result1.GetRawData(), JSTaggedValue(static_cast<double>(1604204297231)).GetRawData());

    JSHandle<EcmaString> str3 =
        thread_->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString("Thu Nov 19 2020 20:18:18 GMT+0800");
    auto ecmaRuntimeCallInfo3 = CreateAndSetRuntimeCallInfo(thread_, 6, JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo3->SetCallArg(0, str3.GetTaggedValue());

    prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo3.get());
    result1 = date::Parse(ecmaRuntimeCallInfo3.get());
    TestHelper::TearDownFrame(thread_, prev);
    ASSERT_EQ(result1.GetRawData(), JSTaggedValue(static_cast<double>(1605788298000)).GetRawData());

    JSHandle<EcmaString> str4 =
        thread_->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString("Thu 03 Jun 2093 04:18 GMT");
    auto ecmaRuntimeCallInfo4 = CreateAndSetRuntimeCallInfo(thread_, 6, JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo4->SetCallArg(0, str4.GetTaggedValue());

    prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo4.get());
    result1 = date::Parse(ecmaRuntimeCallInfo4.get());
    TestHelper::TearDownFrame(thread_, prev);
    ASSERT_EQ(result1.GetRawData(), JSTaggedValue(static_cast<double>(3894841080000)).GetRawData());

    auto ecmaRuntimeCallInfo5 = CreateAndSetRuntimeCallInfo(thread_, 6, JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo5->SetCallArg(0, JSTaggedValue::Null());

    prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo5.get());
    result1 = date::Parse(ecmaRuntimeCallInfo5.get());
    TestHelper::TearDownFrame(thread_, prev);
    ASSERT_EQ(result1.GetRawData(), JSTaggedValue(static_cast<double>(base::NAN_VALUE)).GetRawData());
}

TEST_F(BuiltinsDateTest, ToDateString)
{
    JSHandle<EcmaString> expectValue =
        thread_->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString("Tue Nov 06 2018");
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);
    SetAllYearAndHours(thread_, jsDate);

    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 4, jsDate.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    JSTaggedValue result = date::proto::ToDateString(ecmaRuntimeCallInfo.get());
    TestHelper::TearDownFrame(thread_, prev);

    ASSERT_TRUE(result.IsString());
    ASSERT_TRUE(EcmaString::StringsAreEqual(reinterpret_cast<EcmaString *>(result.GetRawData()), *expectValue));
}

TEST_F(BuiltinsDateTest, ToISOString)
{
    JSHandle<EcmaString> expectValue =
        thread_->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString("2020-11-19T12:18:18.132Z");
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);
    JSDate::Cast(jsDate.GetTaggedValue().GetTaggedObject())->SetTimeValue(thread_, JSTaggedValue(1605788298132.0));
    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 4, jsDate.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    JSTaggedValue result1 = date::proto::ToISOString(ecmaRuntimeCallInfo.get());
    TestHelper::TearDownFrame(thread_, prev);
    ASSERT_TRUE(result1.IsString());
    ASSERT_TRUE(EcmaString::StringsAreEqual(reinterpret_cast<EcmaString *>(result1.GetRawData()), *expectValue));
}

TEST_F(BuiltinsDateTest, ToISOStringMinus)
{
    JSHandle<EcmaString> expectValue =
        thread_->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString("1831-12-02T21:47:18.382Z");
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);
    JSDate::Cast(jsDate.GetTaggedValue().GetTaggedObject())->SetTimeValue(thread_, JSTaggedValue(-4357419161618.0));

    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 4, jsDate.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    JSTaggedValue result1 = date::proto::ToISOString(ecmaRuntimeCallInfo.get());
    TestHelper::TearDownFrame(thread_, prev);
    ASSERT_TRUE(result1.IsString());
    ASSERT_TRUE(EcmaString::StringsAreEqual(reinterpret_cast<EcmaString *>(result1.GetRawData()), *expectValue));
}

// test toJSON and toPrimitive
TEST_F(BuiltinsDateTest, ToJSON)
{
    JSHandle<EcmaString> expectValue =
        thread_->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString("2020-11-19T12:18:18.132Z");
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);
    jsDate->SetTimeValue(thread_, JSTaggedValue(1605788298132.0));
    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 4, jsDate.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    JSTaggedValue result1 = date::proto::ToJSON(ecmaRuntimeCallInfo.get());
    TestHelper::TearDownFrame(thread_, prev);
    ASSERT_TRUE(result1.IsString());
    ASSERT_TRUE(EcmaString::StringsAreEqual(reinterpret_cast<EcmaString *>(result1.GetRawData()), *expectValue));
}

TEST_F(BuiltinsDateTest, ToJSONMinus)
{
    JSHandle<EcmaString> expectValue =
        thread_->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString("1831-12-02T21:47:18.382Z");
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);
    jsDate->SetTimeValue(thread_, JSTaggedValue(-4357419161618.0));
    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 4, jsDate.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    JSTaggedValue result1 = date::proto::ToJSON(ecmaRuntimeCallInfo.get());
    ASSERT_TRUE(result1.IsString());
    ASSERT_TRUE(EcmaString::StringsAreEqual(reinterpret_cast<EcmaString *>(result1.GetRawData()), *expectValue));
}

static PandaString GetLocalTime(JSHandle<JSDate> jsDate, int64_t localMin)
{
    PandaString localTime;
    localMin = JSDate::GetLocalOffsetFromOS(localMin, true);
    if (static_cast<int64_t>(JSDate::Cast(jsDate.GetTaggedValue().GetTaggedObject())->GetTimeValue().GetDouble()) <
            CHINA_BEFORE_1900_MS &&
        localMin == CHINA_AFTER_1901_MIN) {
        localMin = CHINA_BEFORE_1901_MIN;
    }
    if (localMin >= 0) {
        localTime += PLUS;
    } else if (localMin < 0) {
        localTime += NEG;
        localMin = -localMin;
    }
    localTime = localTime + JSDate::StrToTargetLength(ToPandaString(localMin / MINUTE_PER_HOUR), STR_LENGTH_OTHERS);
    return localTime + JSDate::StrToTargetLength(ToPandaString(localMin % MINUTE_PER_HOUR), STR_LENGTH_OTHERS);
}

TEST_F(BuiltinsDateTest, ToString)
{
    int localMin = 0;
    PandaString localTime;

    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);
    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 4, jsDate.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());

    SetAllYearAndHours(thread_, jsDate);
    localTime = GetLocalTime(jsDate, localMin);
    JSTaggedValue result1 = date::proto::ToString(ecmaRuntimeCallInfo.get());
    ASSERT_TRUE(result1.IsString());
    TestHelper::TearDownFrame(thread_, prev);
    JSHandle<EcmaString> result1Val(thread_, reinterpret_cast<EcmaString *>(result1.GetRawData()));
    PandaString str = "Tue Nov 06 2018 18:10:06 GMT" + localTime;
    JSHandle<EcmaString> strHandle = thread_->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString(str);
    ASSERT_TRUE(EcmaString::StringsAreEqual(*result1Val, *strHandle));

    JSHandle<JSDate> jsDate1 = JSDateCreateTest(thread_);
    auto ecmaRuntimeCallInfo1 = CreateAndSetRuntimeCallInfo(thread_, 4, jsDate1.GetTaggedValue());
    prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo1.get());

    SetAll1(thread_, jsDate1);
    localTime = GetLocalTime(jsDate1, localMin);
    JSTaggedValue result2 = date::proto::ToString(ecmaRuntimeCallInfo1.get());
    ASSERT_TRUE(result2.IsString());
    TestHelper::TearDownFrame(thread_, prev);
    JSHandle<EcmaString> result2Val(thread_, reinterpret_cast<EcmaString *>(result2.GetRawData()));
    str = "Mon Dec 31 1900 23:54:16 GMT" + localTime;
    strHandle = thread_->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString(str);
    ASSERT_TRUE(EcmaString::StringsAreEqual(*result2Val, *strHandle));

    JSHandle<JSDate> jsDate2 = JSDateCreateTest(thread_);
    auto ecmaRuntimeCallInfo2 = CreateAndSetRuntimeCallInfo(thread_, 4, jsDate2.GetTaggedValue());
    prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo2.get());

    SetAll2(thread_, jsDate2);
    localTime = GetLocalTime(jsDate, localMin);
    JSTaggedValue result3 = date::proto::ToString(ecmaRuntimeCallInfo2.get());
    ASSERT_TRUE(result3.IsString());
    TestHelper::TearDownFrame(thread_, prev);
    JSHandle<EcmaString> result3Val(thread_, reinterpret_cast<EcmaString *>(result3.GetRawData()));
    str = "Tue Jan 01 1901 00:03:21 GMT" + localTime;
    strHandle = thread_->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString(str);
    ASSERT_TRUE(EcmaString::StringsAreEqual(*result3Val, *strHandle));
}

TEST_F(BuiltinsDateTest, ToTimeString)
{
    int localMin = 0;
    PandaString localTime;

    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);
    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 4, jsDate.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());

    SetAllYearAndHours(thread_, jsDate);
    localTime = GetLocalTime(jsDate, localMin);
    JSTaggedValue result1 = date::proto::ToTimeString(ecmaRuntimeCallInfo.get());
    ASSERT_TRUE(result1.IsString());
    JSHandle<EcmaString> result1Val(thread_, reinterpret_cast<EcmaString *>(result1.GetRawData()));
    PandaString str = "18:10:06 GMT" + localTime;
    JSHandle<EcmaString> strHandle = thread_->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString(str);
    ASSERT_TRUE(EcmaString::StringsAreEqual(*result1Val, *strHandle));

    JSHandle<JSDate> jsDate1 = JSDateCreateTest(thread_);
    auto ecmaRuntimeCallInfo1 = CreateAndSetRuntimeCallInfo(thread_, 4, jsDate1.GetTaggedValue());
    prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo1.get());
    SetAll1(thread_, jsDate1);
    localTime = GetLocalTime(jsDate1, localMin);
    JSTaggedValue result2 = date::proto::ToTimeString(ecmaRuntimeCallInfo1.get());
    ASSERT_TRUE(result2.IsString());
    JSHandle<EcmaString> result2Val(thread_, reinterpret_cast<EcmaString *>(result2.GetRawData()));
    str = "23:54:16 GMT" + localTime;
    strHandle = thread_->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString(str);
    ASSERT_TRUE(EcmaString::StringsAreEqual(*result2Val, *strHandle));
    JSHandle<JSDate> jsDate2 = JSDateCreateTest(thread_);
    auto ecmaRuntimeCallInfo2 = CreateAndSetRuntimeCallInfo(thread_, 4, jsDate2.GetTaggedValue());
    prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo2.get());
    SetAll2(thread_, jsDate2);
    localTime = GetLocalTime(jsDate, localMin);
    JSTaggedValue result3 = date::proto::ToTimeString(ecmaRuntimeCallInfo2.get());
    ASSERT_TRUE(result3.IsString());
    JSHandle<EcmaString> result3Val(thread_, reinterpret_cast<EcmaString *>(result3.GetRawData()));
    str = "00:03:21 GMT" + localTime;
    strHandle = thread_->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString(str);
    ASSERT_TRUE(EcmaString::StringsAreEqual(*result3Val, *strHandle));
}

TEST_F(BuiltinsDateTest, ToUTCString)
{
    JSHandle<EcmaString> expectValue =
        thread_->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString("Thu, 19 Nov 2020 12:18:18 GMT");
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);
    JSDate::Cast(jsDate.GetTaggedValue().GetTaggedObject())->SetTimeValue(thread_, JSTaggedValue(1605788298132.0));
    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 4, jsDate.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    JSTaggedValue result1 = date::proto::ToUTCString(ecmaRuntimeCallInfo.get());
    ASSERT_TRUE(result1.IsString());
    ASSERT_TRUE(EcmaString::StringsAreEqual(reinterpret_cast<EcmaString *>(result1.GetRawData()), *expectValue));
}

TEST_F(BuiltinsDateTest, ToUTCStringMinus)
{
    JSHandle<EcmaString> expectValue =
        thread_->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString("Fri, 02 Dec 1831 21:47:18 GMT");
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);
    JSDate::Cast(jsDate.GetTaggedValue().GetTaggedObject())->SetTimeValue(thread_, JSTaggedValue(-4357419161618.0));
    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 4, jsDate.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    JSTaggedValue result1 = date::proto::ToUTCString(ecmaRuntimeCallInfo.get());
    ASSERT_TRUE(result1.IsString());
    ASSERT_TRUE(EcmaString::StringsAreEqual(reinterpret_cast<EcmaString *>(result1.GetRawData()), *expectValue));
}

TEST_F(BuiltinsDateTest, ValueOf)
{
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);
    JSDate::Cast(jsDate.GetTaggedValue().GetTaggedObject())->SetTimeValue(thread_, JSTaggedValue(1605788298132.0));
    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 4, jsDate.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    JSTaggedValue result1 = date::proto::ValueOf(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result1.GetRawData(), JSTaggedValue(static_cast<double>(1605788298132)).GetRawData());
}

TEST_F(BuiltinsDateTest, ValueOfMinus)
{
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);
    JSDate::Cast(jsDate.GetTaggedValue().GetTaggedObject())->SetTimeValue(thread_, JSTaggedValue(-4357419161618.0));
    auto ecmaRuntimeCallInfo = CreateAndSetRuntimeCallInfo(thread_, 4, jsDate.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    JSTaggedValue result1 = date::proto::ValueOf(ecmaRuntimeCallInfo.get());
    ASSERT_EQ(result1.GetRawData(), JSTaggedValue(static_cast<double>(-4357419161618)).GetRawData());
}

TEST_F(BuiltinsDateTest, DateConstructor)
{
    // case1: test new target is undefined.
    JSHandle<JSDate> jsDate = JSDateCreateTest(thread_);
    JSHandle<GlobalEnv> globalEnv = thread_->GetEcmaVM()->GetGlobalEnv();
    JSHandle<JSFunction> dateFunc(globalEnv->GetDateFunction());
    auto ecmaRuntimeCallInfo1 = CreateAndSetRuntimeCallInfo(thread_, 4, JSTaggedValue::Undefined());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo1.get());
    JSTaggedValue result1 = date::DateConstructor(ecmaRuntimeCallInfo1.get());
    TestHelper::TearDownFrame(thread_, prev);
    ASSERT_TRUE(result1.IsString());

    // case2: length == 0
    auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread_, jsDate.GetTaggedValue(), 4);
    ecmaRuntimeCallInfo2->SetFunction(dateFunc.GetTaggedValue());
    ecmaRuntimeCallInfo2->SetThis(jsDate.GetTaggedValue());

    prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo2.get());
    JSTaggedValue result2 = date::DateConstructor(ecmaRuntimeCallInfo2.get());
    TestHelper::TearDownFrame(thread_, prev);
    ASSERT_TRUE(result2.IsObject());

    // case3: length == 1
    auto ecmaRuntimeCallInfo3 = TestHelper::CreateEcmaRuntimeCallInfo(thread_, jsDate.GetTaggedValue(), 6);
    ecmaRuntimeCallInfo3->SetFunction(dateFunc.GetTaggedValue());
    ecmaRuntimeCallInfo3->SetThis(jsDate.GetTaggedValue());
    ecmaRuntimeCallInfo3->SetCallArg(0, JSTaggedValue(static_cast<double>(2018)));

    prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo3.get());
    JSTaggedValue result3 = date::DateConstructor(ecmaRuntimeCallInfo3.get());
    TestHelper::TearDownFrame(thread_, prev);
    ASSERT_TRUE(result3.IsObject());

    date::proto::SetFullYear(ecmaRuntimeCallInfo3.get());
    JSTaggedValue result4 = date::proto::GetFullYear(ecmaRuntimeCallInfo3.get());
    ASSERT_EQ(result4.GetRawData(), JSTaggedValue(static_cast<double>(2018)).GetRawData());

    // case3: length > 1
    auto ecmaRuntimeCallInfo4 = TestHelper::CreateEcmaRuntimeCallInfo(thread_, jsDate.GetTaggedValue(), 8);
    ecmaRuntimeCallInfo4->SetFunction(dateFunc.GetTaggedValue());
    ecmaRuntimeCallInfo4->SetThis(jsDate.GetTaggedValue());
    ecmaRuntimeCallInfo4->SetCallArg(0, JSTaggedValue(static_cast<double>(2018)));
    ecmaRuntimeCallInfo4->SetCallArg(1, JSTaggedValue(static_cast<double>(10)));

    prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo4.get());
    JSTaggedValue result5 = date::DateConstructor(ecmaRuntimeCallInfo4.get());
    ASSERT_TRUE(result5.IsObject());

    SetAllYearAndHours(thread_, jsDate);
    date::proto::SetFullYear(ecmaRuntimeCallInfo4.get());
    JSTaggedValue result6 = date::proto::GetFullYear(ecmaRuntimeCallInfo4.get());
    ASSERT_EQ(result6.GetRawData(), JSTaggedValue(static_cast<double>(2018)).GetRawData());
    JSTaggedValue result7 = date::proto::GetMonth(ecmaRuntimeCallInfo4.get());
    ASSERT_EQ(result7.GetRawData(), JSTaggedValue(static_cast<double>(10)).GetRawData());
}
}  // namespace ark::test

// NOLINTEND(readability-magic-numbers)
